package com.snack.system.service.impl;

import com.snack.common.core.constant.UserConstants;
import com.snack.common.core.exception.ServiceException;
import com.snack.common.core.text.Convert;
import com.snack.common.core.utils.StringUtils;
import com.snack.common.core.utils.dif.DifUtils;
import com.snack.common.core.utils.uuid.IdUtils;
import com.snack.common.redis.service.RedisService;
import com.snack.system.domain.TsGoodsType;
import com.snack.system.domain.TsGoodsTypeParam;
import com.snack.system.domain.vo.TreeSelect;
import com.snack.system.mapper.TsGoodsTypeMapper;
import com.snack.system.mapper.TsGoodsTypeParamMapper;
import com.snack.system.service.ITsGoodsTypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 商品类型Service业务层处理
 * 
 * @author snack
 * @date 2022-09-18
 */
@Service
public class TsGoodsTypeServiceImpl implements ITsGoodsTypeService 
{
    public static final String GOODS_TYPE_CACHE_KEY = "goods_type_cache_key";
    @Autowired
    private TsGoodsTypeMapper goodsTypeMapper;
    @Autowired
    private TsGoodsTypeParamMapper goodsTypeParamMapper;
    @Autowired
    private RedisService redisService;

    /**
     * 查询商品类型
     * 
     * @param goodsTypeId 商品类型主键
     * @return 商品类型
     */
    @Override
    public TsGoodsType selectTypeById(Long goodsTypeId)
    {
        return goodsTypeMapper.selectTypeById(goodsTypeId);
    }

    /**
     * 根据ID查询所有子类型（正常状态）
     *
     * @param goodsTypeId 类型ID
     * @return 子类型数
     */
    @Override
    public int selectNormalChildrenById(Long goodsTypeId){
        return goodsTypeMapper.selectNormalChildrenById(goodsTypeId);
    }

    /**
     * 查询商品类型列表
     * 
     * @param goodsType 商品类型
     * @return 商品类型
     */
    @Override
    public List<TsGoodsType> selectList(TsGoodsType goodsType)
    {
        return goodsTypeMapper.selectList(goodsType);
    }

    /**
     * 查询所有类型数据
     * @return 商品类型集合
     */
    @Override
    public List<TsGoodsType> selectAllList(){
        List<TsGoodsType> list = redisService.getCacheList(GOODS_TYPE_CACHE_KEY);
        if (StringUtils.isNotEmpty(list)){
            return list;
        }
        TsGoodsType goodsType = new TsGoodsType();
        goodsType.setStatus(UserConstants.NORMAL);
        list = this.selectList(goodsType);
        redisService.setCacheList(GOODS_TYPE_CACHE_KEY,list);
        return list;
    }

    /**
     * 构建前端所需要树结构
     *
     * @param goodsTypes 类型列表
     * @return 树结构列表
     */
    @Override
    public List<TsGoodsType> buildTree(List<TsGoodsType> goodsTypes) {
        List<TsGoodsType> returnList = new ArrayList<TsGoodsType>();
        List<Long> tempList = new ArrayList<Long>();
        for (TsGoodsType type : goodsTypes)
        {
            tempList.add(type.getGoodsTypeId());
        }
        for (Iterator<TsGoodsType> iterator = goodsTypes.iterator(); iterator.hasNext();)
        {
            TsGoodsType next = iterator.next();
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!tempList.contains(next.getParentId()))
            {
                recursionFn(goodsTypes, next);
                returnList.add(next);
            }
        }
        if (returnList.isEmpty())
        {
            returnList = goodsTypes;
        }
        return returnList;
    }

    /**
     * 构建前端所需要下拉树结构
     *
     * @param goodsTypes 类型列表
     * @return 下拉树结构列表
     */
    @Override
    public List<TreeSelect> buildTreeSelect(List<TsGoodsType> goodsTypes) {
        List<TsGoodsType> deptTrees = buildTree(goodsTypes);
        return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
    }

    /**
     * 通过goodsTypeId 查询属性列表
     * @param goodsTypeId 商品类型主键id
     * @return
     */
    @Override
    public List<TsGoodsTypeParam> getParamList(Long goodsTypeId) {
        return goodsTypeParamMapper.selectByGoodsTypeId(goodsTypeId);
    }

    /**
     * 校验类型名称是否唯一
     *
     * @param goodsType 类型信息
     * @return 结果
     */
    @Override
    public String checkNameUnique(TsGoodsType goodsType){
        if (StringUtils.isNull(goodsType.getParentId())){
            goodsType.setParentId(0L);
        }
        Long goodsTypeId = StringUtils.isNull(goodsType.getGoodsTypeId()) ? -1L : goodsType.getGoodsTypeId();
        TsGoodsType info = goodsTypeMapper.checkNameUnique(goodsType.getTypeName(), goodsType.getParentId());
        if (StringUtils.isNotNull(info) && info.getGoodsTypeId().longValue() != goodsTypeId.longValue())
        {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 是否存在类型子节点
     *
     * @param goodsTypeId 类型ID
     * @return 结果
     */
    @Override
    public boolean hasChildById(Long goodsTypeId){
        int result = goodsTypeMapper.hasChildById(goodsTypeId);
        return result > 0;
    }

    /**
     * 查询类型是否存在数据
     *
     * @param goodsTypeId 类型ID
     * @return 结果 true 存在 false 不存在
     */
    @Override
    public boolean checkExistData(Long goodsTypeId){
        int result = goodsTypeMapper.checkExistData(goodsTypeId);
        return result > 0;
    }

    /**
     * 新增商品类型
     * 
     * @param goodsType 商品类型
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public int insert(TsGoodsType goodsType)
    {
        TsGoodsType info = goodsTypeMapper.selectSimpleById(goodsType.getParentId());
        if (StringUtils.isNull(info)){
            goodsType.setAncestors("0");
        }else if (!UserConstants.NORMAL.equals(info.getStatus())){
            // 如果父节点不为正常状态,则不允许新增子节点
            throw new ServiceException("商品类型停用，不允许新增");
        }else{
            goodsType.setAncestors(info.getAncestors() + "," + goodsType.getParentId());
        }
        int rows = goodsTypeMapper.insertTsGoodsType(goodsType);
        //新增属性字段
        insertParam(goodsType);
        removeCache();
        return rows;
    }

    /**
     * 修改商品类型
     * 
     * @param goodsType 商品类型
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public int update(TsGoodsType goodsType)
    {
        if(StringUtils.isNull(goodsType.getGoodsTypeId())){
            throw new ServiceException("请传入商品类型id");
        }
        TsGoodsType newParentType = goodsTypeMapper.selectTypeById(goodsType.getParentId());
        TsGoodsType oldType = goodsTypeMapper.selectTypeById(goodsType.getGoodsTypeId());
        String newAncestors = StringUtils.isNotNull(newParentType) ? (newParentType.getAncestors() + "," + newParentType.getGoodsTypeId()) : "0";
        String oldAncestors = oldType.getAncestors();

        goodsType.setAncestors(newAncestors);
        updateChildren(goodsType.getGoodsTypeId(), newAncestors, oldAncestors);

        int result = goodsTypeMapper.updateTsGoodsType(goodsType);
        goodsType.setStatus(StringUtils.isNotEmpty(goodsType.getStatus()) ? goodsType.getStatus() : oldType.getStatus());
        if (UserConstants.NORMAL.equals(goodsType.getStatus())){
            // 如果该类型是启用状态，则启用该类型的所有上级类型
            updateParentStatusNormal(goodsType);
        }

        //更改属性
        updateParam(goodsType);
        removeCache();
        return result;
    }

    /**
     * 删除商品类型信息
     *
     * @param goodsTypeId 商品类型ID
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public int deleteById(Long goodsTypeId)
    {
        goodsTypeParamMapper.deleteGoodsTypeId(goodsTypeId);
        int rows = goodsTypeMapper.deleteByTypeId(goodsTypeId);
        removeCache();
        return rows;
    }

    /**
     * 移除设备缓存
     */
    @Override
    public void removeCache(){
        redisService.deleteObject(GOODS_TYPE_CACHE_KEY);
    }


    /**
     * 修改该类型的父级类型状态
     *
     * @param goodsType 当前类型
     */
    private void updateParentStatusNormal(TsGoodsType goodsType)
    {
        String ancestors = goodsType.getAncestors();
        Long[] ids = Convert.toLongArray(ancestors);
        goodsTypeMapper.updateStatusNormal(ids);
    }
    /**
     * 修改子元素关系
     *
     * @param goodsTypeId 被修改的类型ID
     * @param newAncestors 新的父ID集合
     * @param oldAncestors 旧的父ID集合
     */
    private void updateChildren(Long goodsTypeId, String newAncestors, String oldAncestors)
    {
        List<TsGoodsType> children = goodsTypeMapper.selectChildrenById(goodsTypeId);
        for (TsGoodsType child : children)
        {
            child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
        }
        if (children.size() > 0)
        {
            goodsTypeMapper.updateChildren(children);
        }
    }

    //=============================== 构建树结构部分 ===========================

    /**
     * 递归列表
     */
    private void recursionFn(List<TsGoodsType> list, TsGoodsType t)
    {
        // 得到子节点列表
        List<TsGoodsType> childList = getChildList(list, t);
        t.setChildren(childList);
        for (TsGoodsType tChild : childList)
        {
            if (hasChild(list, tChild))
            {
                recursionFn(list, tChild);
            }
        }
    }

    /**
     * 得到子节点列表
     */
    private List<TsGoodsType> getChildList(List<TsGoodsType> list, TsGoodsType t)
    {
        List<TsGoodsType> tlist = new ArrayList<TsGoodsType>();
        Iterator<TsGoodsType> it = list.iterator();
        while (it.hasNext())
        {
            TsGoodsType n = it.next();
            if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getGoodsTypeId().longValue())
            {
                tlist.add(n);
            }
        }
        return tlist;
    }

    /**
     * 判断是否有子节点
     */
    private boolean hasChild(List<TsGoodsType> list, TsGoodsType t)
    {
        return getChildList(list, t).size() > 0 ? true : false;
    }

    //=============================== 自定义字段部分 ===========================

    /**
     * 新增属性字段
     * @param goodsType
     * @return
     */
    private void insertParam(TsGoodsType goodsType){
        @Valid List<TsGoodsTypeParam> list = goodsType.getGoodsTypeParamList();
        if (StringUtils.isNotEmpty(list)){
            setAndInsertParam(goodsType,list);
        }
    }
    private void setAndInsertParam(TsGoodsType goodsType,List<TsGoodsTypeParam> list){
        list.forEach((item)->{
            item.setGoodsTypeId(goodsType.getGoodsTypeId());
            item.setCode(IdUtils.fastSimpleUUID());
        });
        goodsTypeParamMapper.insertBatch(list);
    }

    /**
     * 更改属性字段
     * @param goodsType
     */
    private void updateParam(TsGoodsType goodsType){
        @Valid List<TsGoodsTypeParam> list = goodsType.getGoodsTypeParamList();
        if (StringUtils.isNotEmpty(list)){
            List<TsGoodsTypeParam> oldList = goodsTypeParamMapper.selectByGoodsTypeId(goodsType.getGoodsTypeId());
            if (StringUtils.isEmpty(oldList)){
                setAndInsertParam(goodsType,list);
                return;
            }
            Map<Integer, List<TsGoodsTypeParam>> listDiff = DifUtils.findListDiff(list, oldList);
            if (StringUtils.isNotEmpty(listDiff.get(0))){
                setAndInsertParam(goodsType,listDiff.get(0));
            }
            if (StringUtils.isNotEmpty(listDiff.get(1))){
                goodsTypeParamMapper.updateBatch(listDiff.get(1));
            }
            if (StringUtils.isNotEmpty(listDiff.get(2))){
                goodsTypeParamMapper.deleteBatch(listDiff.get(2));
            }
        }else{
            goodsTypeParamMapper.deleteGoodsTypeId(goodsType.getGoodsTypeId());
        }
    }
}
